/**
 * @author Samuel Gonzalez
 * @version 1.0.6 Thu May 10, 2012 10:04PM GMT-400
 */

/*
 * Copyright (C) 2011  Samuel Gonzalez, PR
 * BenchGraph. Generates graphics and HTML tables based on HTTPERF output.
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 * 
 * In addition, as a special exception, the copyright holders give permission
 * to link the code of this work with the OpenSSL project's "OpenSSL" library
 * (or with modified versions of it that use the same license as the "OpenSSL" 
 * library), and distribute linked combinations including the two.  You must
 * obey the GNU General Public License in all respects for all of the code
 * used other than "OpenSSL".  If you modify this file, you may extend this
 * exception to your version of the file, but you are not obligated to do so.
 * If you do not wish to do so, delete this exception statement from your
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 
 */

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Olio {
	private final String DIRECTORY = "./";
	private final String FILENAME = "FILENAME";
	private final String FILEFORMAT = "XML";
	
	private String directory;
	private String filename;
	private String fileformat;
	private ArrayList<ArrayList<String>> data;
	
	/**
	 * Initialize attributes to default values
	 */
	public Olio(){
		this.directory = this.DIRECTORY;
		this.filename = this.FILENAME;
		this.fileformat = this.FILEFORMAT;
		this.data = new ArrayList<ArrayList<String>>();
	}
	
	/**
	 * Initialize attributes to received values.
	 * @param directory - file's directory
	 * @param filename - file's name
	 * @param fileformat - file's format (type)
	 */
	public Olio(String directory, String filename, String fileformat){
		this.setDirectory(directory);
		this.setFilename(filename);
		this.setFileformat(fileformat);
		this.data = new ArrayList<ArrayList<String>>();
	}
	
	/**
	 * Return read data
	 * @return data
	 */
	public ArrayList<ArrayList<String>> getData(){
		return this.data;
	}
	
	/**
	 * Return file's directory
	 * @return directory
	 */
	public String getDirectory(){
		return this.directory;
	}
	
	/**
	 * Set directory
	 * @param directory - file's directory
	 */
	public void setDirectory(String directory){
		this.directory = (directory != null)? directory : this.DIRECTORY;
	}
	
	/**
	 * Return file's name
	 * @return filename
	 */
	public String getFilename(){
		return this.filename;
	}
	
	/**
	 * Set file's name
	 * @param filename
	 */
	public void setFilename(String filename){
		this.filename = (filename != null)? filename : this.FILENAME;
	}
	
	/**
	 * Return file's format (type)
	 * @return fileformat
	 */
	public String getFileformat(){
		return this.fileformat;
	}
	
	/**
	 * Set file's format
	 * @param fileformat
	 */
	public void setFileformat(String fileformat){
		this.fileformat = (fileformat != null)? fileformat : this.FILEFORMAT;
	}
	
	/**
	 * Parse xml file data
	 */
	public void loadFile(){
		try {

			// Moves file pointer to third line
			Scanner file = new Scanner(new File(this.directory + this.filename + "." + this.fileformat));
			for(int i = 0; i < 2; i++)
				file.nextLine();
			// Reads third line. Uses data to know if file was exported by OLIO.
			if(! file.nextLine().equalsIgnoreCase("<BENCHRESULTS>")){
				Console.wln("File specified is not an OLIO file.");
				file.close();
				System.exit(1);
			}
			file.close();
			
			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser saxParser = factory.newSAXParser();

			DefaultHandler handler = new DefaultHandler() {

				public void startElement(String uri, String localName,String qName, 
						Attributes attributes){

					if(qName.equalsIgnoreCase("BENCHSUMMARY") || 
							qName.equalsIgnoreCase("DRIVERSUMMARY")) {
						data.add(new ArrayList<String>());
						data.get(data.size() - 1).add(attributes.getValue(0));
					} else if(qName.equalsIgnoreCase("DESCRIPTION")){
						data.add(new ArrayList<String>());
					} else if(qName.equalsIgnoreCase("OPERATION")){
						data.add(new ArrayList<String>());
						data.get(data.size() - 1).add(attributes.getValue(0));
					} else if(!qName.equalsIgnoreCase("BENCHRESULTS") &&
							!qName.equalsIgnoreCase("STAT") &&
							!qName.equalsIgnoreCase("CUSTOMSTATS") &&
							!qName.equalsIgnoreCase("RESPONSETIMES") &&
							!qName.equalsIgnoreCase("DELAYTIMES")){
						data.get(data.size() - 1).add(qName.trim());
					}
				}

				public void characters(char ch[], int start, int length) throws SAXException {
					if(data.size() > 0){
						if(data.get(data.size() - 1) != null){
							data.get(data.size() - 1).add(new String(ch, start, length).trim());
						}
					}
				}

			};

			saxParser.parse(this.directory + this.filename + "." + this.fileformat, handler);
			cleanUp();
		} catch (IllegalArgumentException iae) {
			Console.wln("Illegal path provided.");
			System.exit(1);
		} catch (SAXException saxe) {
			Console.wln(saxe.getMessage().toString());
			System.exit(1);
		} catch (IOException ioe) {
			Console.wln(ioe.getMessage().toString());
			System.exit(1);
		} catch (ParserConfigurationException pce) {
			Console.wln("Configuration Error.");
			System.exit(1);
		}
	}
	
	/**
	 * Perform some clean up on data list
	 */
	private void cleanUp(){
		
		// Clean up
		for(int i = 0; i < data.size(); i++){
			ArrayList<String> arr = new ArrayList<String>();
			for(int j = 0; j < data.get(i).size(); j++){
				if(data.get(i) != null && data.get(i).get(j) != null){
					if(!data.get(i).get(j).isEmpty()){
						if(data.get(i).get(j).equalsIgnoreCase(">") || data.get(i).get(j).equalsIgnoreCase("<")){
							String tmp = data.get(i).get(j) + " " + data.get(i).get(j + 1);
							arr.add(tmp);
							data.get(i).remove(j + 1);
						} else {
							arr.add(data.get(i).get(j));
						}
					}
				}
			}
			data.set(i, arr);
		}
		
		// Removes first <mix>
		data.get(1).remove(data.get(1).size() - 1); // 1 - driverSummary List

		// Concatenate corresponding name (MIX, RESPONSE TIMES, DELAYTIMES)
		String[] arr = { "Mix - ", "Response Times - ", "Delay Times - " };
		
		int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0;
		
		// Add the name the title to each table.
		for(int i = 2; i < 23; i++){
			if(data.get(i).get(0).equalsIgnoreCase("HOMEPAGE")){
				data.get(i).set(0, arr[a++] + data.get(i).get(0));
			} else if(data.get(i).get(0).equalsIgnoreCase("ADDPERSON")){
				data.get(i).set(0, arr[b++] + data.get(i).get(0));
			} else if(data.get(i).get(0).equalsIgnoreCase("ADDEVENT")){
				data.get(i).set(0, arr[c++] + data.get(i).get(0));
			} else if(data.get(i).get(0).equalsIgnoreCase("PERSONDETAIL")){
				data.get(i).set(0, arr[d++] + data.get(i).get(0));
			} else if(data.get(i).get(0).equalsIgnoreCase("EVENTDETAIL")){
				data.get(i).set(0, arr[e++] + data.get(i).get(0));
			} else if(data.get(i).get(0).equalsIgnoreCase("TAGSEARCH")){
				data.get(i).set(0, arr[f++] + data.get(i).get(0));
			} else if(data.get(i).get(0).equalsIgnoreCase("LOGIN")){
				data.get(i).set(0, arr[g++] + data.get(i).get(0));
			}
		}
		
		// Debug purposes
		// Display
/*		for(int i = 0; i < data.size(); i++){
			for(int j = 0; j < data.get(i).size(); j++){
						System.out.println(data.get(i).get(j));
			}
		}*/
	}
}
